home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint99s / bios.c < prev    next >
C/C++ Source or Header  |  1993-01-22  |  21KB  |  932 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * BIOS replacement routines
  9.  */
  10.  
  11. #include "mint.h"
  12. #include "xbra.h"
  13.  
  14. #define UNDEF 0        /* should match definition in tty.c */
  15.  
  16. /* some key definitions */
  17. #define CTRLALT 0xc
  18. #define DEL 0x53    /* scan code of delete key */
  19. #define UNDO 0x61    /* scan code of undo key */
  20.  
  21. /* BIOS device definitions */
  22. #define CONSDEV 2
  23. #define AUXDEV 1
  24.  
  25. /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
  26. #define MAX_BHANDLE    4
  27.  
  28. /* BIOS redirection maps */
  29. const short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
  30. const short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
  31.  
  32. /* tty structures for the BIOS devices -- see biosfs.c */
  33. extern struct tty con_tty, aux_tty, midi_tty;
  34.  
  35. extern int tosvers;    /* from main.c */
  36. char *kbshft;        /* set in main.c */
  37.  
  38. /* some BIOS vectors; note that the routines at these vectors may do nasty
  39.  * things to registers!
  40.  */
  41.  
  42. #define RWABS *((long *)0x476L)
  43. #define MEDIACH *((long *)0x47eL)
  44. #define GETBPB *((long *)0x472L)
  45.  
  46. #if 1
  47. /* these are supposed to be tables holding the addresses of the
  48.  * first 8 BconXXX functions, but in fact only the first 5 are
  49.  * placed here (and device 5 only has Bconout implemented; 
  50.  * we don't use that device (raw console) anyway).
  51.  */
  52.  
  53. #define xconstat ((long *)0x51eL)
  54. #define xconin     ((long *)0x53eL)
  55. #define xcostat ((long *)0x55eL)
  56. #define xconout    ((long *)0x57eL)
  57.  
  58. #define BCOSTAT(dev) \
  59.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  60.        (int)callout1(xcostat[dev], dev) : Bcostat(dev))
  61. #define BCONOUT(dev, c) \
  62.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  63.        callout2(xconout[dev], dev, c) : Bconout(dev, c))
  64. #define BCONSTAT(dev) \
  65.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  66.        (int)callout1(xconstat[dev], dev) : Bconstat(dev))
  67. #define BCONIN(dev) \
  68.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  69.        callout1(xconin[dev], dev) : Bconin(dev))
  70. #else
  71.  
  72. #define BCOSTAT(dev) Bcostat(dev)
  73. #define BCONOUT(dev, c) Bconout(dev, c)
  74. #define BCONSTAT(dev) Bconstat(dev)
  75. #define BCONIN(dev) Bconin(dev)
  76.  
  77. #endif
  78.  
  79. /* variables for monitoring the keyboard */
  80. IOREC_T    *keyrec;        /* keyboard i/o record pointer */
  81. short    kintr = 0;        /* keyboard interrupt pending (see intr.s) */
  82.  
  83. /* Getmpb is not allowed under MiNT */
  84.  
  85. long ARGS_ON_STACK
  86. getmpb(ptr)
  87.     void *ptr;
  88. {
  89.     UNUSED(ptr);
  90.  
  91.     DEBUG(("failed call to Getmpb"));
  92.     return -1;
  93. }
  94.  
  95.  
  96. /*
  97.  * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
  98.  * to get the physical devices, go through u:\dev\
  99.  *
  100.  * A note on translation: all of the bco[n]XXX functions have a "u"
  101.  * variant that is actually what the user calls. For example,
  102.  * ubconstat is the function that gets control after the user does
  103.  * a Bconstat. It figures out what device or file handle is
  104.  * appropriate. Typically, it will be a biosfs file handle; a
  105.  * request is sent to biosfs, and biosfs in turn figures out
  106.  * the "real" device and calls bconstat.
  107.  */
  108.  
  109. /*
  110.  * WARNING: syscall.spp assumes that ubconstat never blocks.
  111.  */
  112. long ARGS_ON_STACK
  113. ubconstat(dev)
  114. int dev;
  115. {
  116.     if (dev < MAX_BHANDLE) {
  117.         FILEPTR *f = curproc->handle[binput[dev]];
  118.         return file_instat(f) ? -1 : 0;
  119.     }
  120.     else
  121.         return bconstat(dev);
  122. }
  123.  
  124. long
  125. bconstat(dev)
  126. int dev;
  127. {
  128.     if (dev == CONSDEV) {
  129.         if (checkkeys()) return 0;
  130.         return (keyrec->head != keyrec->tail) ? -1 : 0;
  131.     }
  132.     if (dev == AUXDEV && has_bconmap)
  133.         dev = curproc->bconmap;
  134.  
  135.     return BCONSTAT(dev);
  136. }
  137.  
  138. /* bconin: input a character */
  139. /*
  140.  * WARNING: syscall.spp assumes that ubconin never
  141.  * blocks if ubconstat returns non-zero.
  142.  */
  143. long ARGS_ON_STACK
  144. ubconin(dev)
  145. int dev;
  146. {
  147.     if (dev < MAX_BHANDLE) {
  148.         FILEPTR *f = curproc->handle[binput[dev]];
  149.         return file_getchar(f, RAW);
  150.     }
  151.     else
  152.         return bconin(dev);
  153. }
  154.  
  155. long
  156. bconin(dev)
  157. int dev;
  158. {
  159.     IOREC_T *k;
  160.     long r;
  161.     short h;
  162.  
  163.     if (dev == CONSDEV) {
  164.         k = keyrec;
  165. again:
  166.         while (k->tail == k->head) {
  167.             yield();
  168.         }
  169.  
  170.         if (checkkeys()) goto again;
  171.  
  172.         h = k->head + 4;
  173.         if (h >= k->buflen)
  174.             h = 0;
  175.         r = *((long *)(k->bufaddr + h));
  176.         k->head = h;
  177.         return r;
  178.     }
  179.     else {
  180.         if (dev == AUXDEV && has_bconmap)
  181.             dev = curproc->bconmap;
  182.  
  183.         if (dev > 0) {
  184.             while (!BCONSTAT(dev)) {
  185.                 yield();
  186.             }
  187.         }
  188.     }
  189.  
  190.     r = BCONIN(dev);
  191.  
  192.     return r;
  193. }
  194.  
  195. /* bconout: output a character.
  196.  * returns 0 for failure, nonzero for success
  197.  */
  198.  
  199. long ARGS_ON_STACK
  200. ubconout(dev, c)
  201. int dev, c;
  202. {
  203.     FILEPTR *f;
  204.     char outp;
  205.  
  206.     if (dev < MAX_BHANDLE) {
  207.         f = curproc->handle[boutput[dev]];
  208.         if (!f) return 0;
  209.         if (is_terminal(f)) {
  210.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  211.         }
  212.         outp = c;
  213.         return (*f->dev->write)(f, &outp, 1L);
  214.     }
  215.     else if (dev == 5) {
  216.         c &= 0x00ff;
  217.         f = curproc->handle[-1];
  218.         if (!f) return 0;
  219.         if (is_terminal(f)) {
  220.             if (c < ' ') {
  221.             /* MW hack for quoted characters */
  222.                 tty_putchar(f, (long)'\033', RAW);
  223.                 tty_putchar(f, (long)'Q', RAW);
  224.             }
  225.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  226.         }
  227.     /* note: we're assuming sizeof(int) == 2 here! */
  228.         outp = c;
  229.         return (*f->dev->write)(f, &outp, 1L);
  230.     } else
  231.         return bconout(dev, c);
  232. }
  233.  
  234. long
  235. bconout(dev, c)
  236. int dev,c;
  237. {
  238.     int statdev;
  239.     long endtime;
  240.     extern long searchtime;    /* in dosdir.c; updated once per second */
  241.  
  242.     if (dev == AUXDEV && has_bconmap) {
  243.         dev = curproc->bconmap;
  244.     }
  245.  
  246. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  247.     if (dev == 3) {        /* MIDI */
  248.         statdev = 4;
  249.     } else if (dev == 4) {
  250.         statdev = 3;
  251.     } else
  252.         statdev = dev;
  253.  
  254. /* provide a 10 second time out */
  255.     if (!BCOSTAT(statdev)) {
  256.         endtime = searchtime + 10;
  257.         do {
  258.             yield();
  259.         } while (!BCOSTAT(statdev) && searchtime < endtime);
  260.         if ( searchtime >= endtime) return 0;
  261.     }
  262.  
  263. /* special case: many text accelerators return a bad value from
  264.  * Bconout, so we ignore the returned value for the console
  265.  */
  266.     if (dev != CONSDEV) {
  267. /* NOTE: if your compiler complains about the next line, then Bconout is
  268.  * improperly declared in your osbind.h header file. it should be returning
  269.  * a long value; some libraries incorrectly have Bconout returning void
  270.  * (or cast the returned value to void)
  271.  */
  272.         return BCONOUT(dev,c);
  273.     } else {
  274.         (void)BCONOUT(dev, c);
  275.         return 1;
  276.     }
  277. }
  278.  
  279. /* rwabs: various disk stuff */
  280.  
  281. /* BUG: Rwabs should respect Dlock */
  282.  
  283. long ARGS_ON_STACK
  284. rwabs(rwflag, buffer, number, recno, dev, lrecno)
  285. int rwflag, number, recno, dev;
  286. void *buffer;
  287. long lrecno;
  288. {
  289.     long r;
  290.     extern PROC *dlockproc[];    /* in dosdir.c */
  291.  
  292.     if (dev >= 0 && dev < NUM_DRIVES && dlockproc[dev]) {
  293.         if (dlockproc[dev] != curproc) {
  294.             DEBUG(("Rwabs: device %c is locked", dev+'A'));
  295.             return ELOCKED;
  296.         }
  297.     }
  298.  
  299. /* Note that some (most?) Rwabs device drivers don't bother saving
  300.  * registers, whereas our compiler expects politeness. So we go
  301.  * via callout(), which will save registers for us.
  302.  */
  303.     r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
  304.     return r;
  305. }
  306.  
  307. /* setexc: set exception vector */
  308.  
  309. long ARGS_ON_STACK
  310. setexc(number, vector)
  311. int number;
  312. long vector;
  313. {
  314.     long *place;
  315.     long old;
  316.     extern long save_dos, save_bios, save_xbios;    /* in main.c */
  317.     extern int no_mem_prot;                /* in main.c */
  318.  
  319.     place = (long *)(((long)number) << 2);
  320.     if (number == 0x21)                /* trap_1 */
  321.         old = save_dos;
  322.     else if (number == 0x2d)            /* trap_13 */
  323.         old = save_bios;
  324.     else if (number == 0x2e)            /* trap_14 */
  325.         old = save_xbios;
  326.     else if (number == 0x101)
  327.         old = (long)curproc->criticerr;        /* critical error vector */
  328.     else if (number == 0x102)
  329.         old = curproc->ctxt[SYSCALL].term_vec;    /* GEMDOS term vector */
  330.     else
  331.         old = *place;
  332.  
  333.     if (vector > 0) {
  334.     /* validate vector; this will cause a bus error if mem
  335.      * protection is on and the current process doesn't have
  336.      * access to the memory
  337.      */
  338.         if (*((long *)vector) == 0xDEADBEEFL)
  339.             return old;
  340.  
  341.         if (number == 0x21)
  342.             save_dos = vector;
  343.         else if (number == 0x2d)
  344.             save_bios = vector;
  345.         else if (number == 0x2e)
  346.             save_xbios = vector;
  347.         else if (number == 0x102)
  348.             curproc->ctxt[SYSCALL].term_vec = vector;
  349.         else if (number == 0x101) {
  350.             long mintcerr;
  351.  
  352.         /*
  353.          * problem: lots of TSR's look for the Setexc(0x101,...)
  354.           * that the AES does at startup time; so we have
  355.          * to pass it along.
  356.          */
  357.             mintcerr = (long) Setexc(0x101, (void *)vector);
  358.             curproc->criticerr = (long ARGS_ON_STACK (*) P_((long))) *place;
  359.             *place = mintcerr;
  360.         }
  361.         else {
  362.             if (!no_mem_prot) {
  363.             /*
  364.              * if memory protection is on, the vector should be
  365.              * pointing at supervisor or global memory
  366.              */
  367.                 MEMREGION *r;
  368.  
  369.                 r = addr2region(vector);
  370.                 if (r && get_prot_mode(r) == PROT_P) {
  371.                 DEBUG(("Changing protection to Supervisor because of Setexc"));
  372.                 mark_region(r, PROT_S);
  373.                 }
  374.             }
  375.         /* We would do just *place = vector except that
  376.          * someone else might be intercepting Setexc looking
  377.          * for something in particular...
  378.          */
  379.             old = (long) Setexc(number, (void *)vector);
  380.         }
  381.     }
  382.  
  383.     TRACE(("Setexc %d, %lx -> %lx", number, vector, old));
  384.     return old;
  385. }
  386.  
  387. /* tickcal: return milliseconds per system clock tick */
  388.  
  389. long ARGS_ON_STACK
  390. tickcal()
  391. {
  392.     return (long) (*( (unsigned *) 0x0442L ));
  393. }
  394.  
  395. /* getbpb: get BIOS parameter block */
  396.  
  397. long ARGS_ON_STACK
  398. getbpb(dev)
  399. int dev;
  400. {
  401.     long r;
  402.  
  403. /* we can't trust the Getbpb routine to accurately save all registers,
  404.  * so we do it ourselves
  405.  */
  406.     r = callout(GETBPB, dev);
  407. /* 
  408.  * There is a bug in the  TOS  disk handling routines (well several actually).
  409.  * If the directory size of Getbpb() is returned as zero then the drive 'dies'
  410.  * and wont read any new disks even with the 'ESC' enforced disk change . This
  411.  * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
  412.  * changes the dir size to '1' if it is zero . It may make some non-TOS disks
  413.  * look a bit weird but that's better than killing the drive .
  414.  */
  415.     if (r) {
  416.         if ( ((short *)r)[3] == 0)    /* 0 directory size? */
  417.             ((short *)r)[3] = 1;
  418.     }
  419.     return r;
  420. }
  421.  
  422. /* bcostat: return output device status */
  423.  
  424. /* WARNING: syscall.spp assumes that ubcostat never
  425.  * blocks
  426.  */
  427. long ARGS_ON_STACK
  428. ubcostat(dev)
  429. int dev;
  430. {
  431.     FILEPTR *f;
  432.  
  433. /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
  434.     if (dev == 4) {        /* really the MIDI port */
  435.         f = curproc->handle[boutput[3]];
  436.         return file_outstat(f) ? -1 : 0;
  437.     }
  438.     if (dev == 3)
  439.         return BCOSTAT(dev);
  440.  
  441.     if (dev < MAX_BHANDLE) {
  442.         f = curproc->handle[boutput[dev]];
  443.         return file_outstat(f) ? -1 : 0;
  444.     } else
  445.         return bcostat(dev);
  446. }
  447.  
  448. long
  449. bcostat(dev)
  450. int dev;
  451. {
  452.  
  453.     if (dev == CONSDEV) {
  454.         return -1;
  455.     }
  456.     else if (dev == AUXDEV && has_bconmap) {
  457.         dev = curproc->bconmap;
  458.     }
  459. /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
  460.  * correctly
  461.  */
  462.     else if (dev == 3) dev = 4;
  463.     else if (dev == 4) dev = 3;
  464.  
  465.     return BCOSTAT(dev);
  466. }
  467.  
  468. /* mediach: check for media change */
  469.  
  470. long ARGS_ON_STACK
  471. mediach(dev)
  472. int dev;
  473. {
  474.     long r;
  475.  
  476.     r = callout1(MEDIACH, dev);
  477.     return r;
  478. }
  479.  
  480. /* drvmap: return drives connected to system */
  481.  
  482. long ARGS_ON_STACK
  483. drvmap()
  484. {
  485.     return *( (long *)0x4c2L );
  486. }
  487.  
  488. /* kbshift: return (and possibly change) keyboard shift key status */
  489. /* WARNING: syscall.spp assumes that kbshift never blocks, and never
  490.  * calls any underlying TOS functions
  491.  */
  492. long ARGS_ON_STACK
  493. kbshift(mode)
  494. int mode;
  495. {
  496.     int oldshft;
  497.  
  498.     oldshft = *((unsigned char *)kbshft);
  499.     if (mode >= 0)
  500.         *kbshft = mode;
  501.     return oldshft;
  502. }
  503.  
  504.  
  505. /* special Bconout buffering code:
  506.  * Because system call overhead is so high, programs that do output
  507.  * with Bconout suffer in performance. To compensate for this,
  508.  * Bconout is special-cased in syscall.s, and if possible characters
  509.  * are placed in the 256 byte bconbuf buffer. This buffer is flushed
  510.  * when any system call other than Bconout happens, or when a context
  511.  * switch occurs.
  512.  */
  513.  
  514. short bconbsiz;            /* number of characters in buffer */
  515. unsigned char bconbuf[256];    /* buffer contents */
  516. short bconbdev;            /* BIOS device for which the buffer is valid */
  517.                 /* (-1 means no buffering is active) */
  518.  
  519. /*
  520.  * flush pending BIOS output. Return 0 if some bytes were not successfully
  521.  * written, non-zero otherwise (just like bconout)
  522.  */
  523.  
  524. long ARGS_ON_STACK
  525. bflush()        /* flush bios output */
  526. {
  527.     long ret, bsiz;
  528.     unsigned char *s;
  529.     FILEPTR *f;
  530.     short dev;
  531.     short statdev;
  532.     long lbconbuf[256];
  533.  
  534.     if ((dev = bconbdev) < 0) return 0;
  535.  
  536. /*
  537.  * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
  538.  * This is necessary because if two or more programs try to do
  539.  * buffered BIOS output at the same time, they can get seriously
  540.  * mixed up. We unlock by setting bconbdev to 0.
  541.  *
  542.  * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
  543.  * order to see if we need to do a bflush; if one is already in
  544.  * progress, it's pointless to do this, so we save a bit of
  545.  * time by setting bconbsiz to 0 here.
  546.  */
  547.     bconbdev = -1;
  548.     bsiz = bconbsiz;
  549.     if (bsiz == 0) return 0;
  550.     bconbsiz = 0;
  551.  
  552. /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
  553.     if (dev < MAX_BHANDLE || dev == 5) {
  554.         if (dev == 5)
  555.             f = curproc->handle[-1];
  556.         else
  557.             f = curproc->handle[boutput[dev]];
  558.  
  559.         if (!f) {
  560.             bconbdev = 0;
  561.             return 0;
  562.         }
  563.         if (is_terminal(f)) {
  564.             s = bconbuf;
  565.             if (dev == 5) {
  566.                 while (bsiz-- > 0) {
  567.                 if (*s < ' ') {
  568.             /* use ESC-Q to quote control character */
  569.                     (void)tty_putchar(f, (long)'\033',
  570.                                 RAW);
  571.                     (void)tty_putchar(f, (long)'Q',
  572.                                 RAW);
  573.                 }
  574.                 (void) tty_putchar(f, (long)*s++, RAW);
  575.                 }
  576.             } else {
  577. #if 1
  578.                 long *where, nbytes;
  579.  
  580. /* the tty_putchar should set up terminal modes correctly */
  581.                 (void) tty_putchar(f, (long)*s++, RAW);
  582.                 where = lbconbuf;
  583.                 nbytes = 0;
  584.                 while (--bsiz > 0) {
  585.                 *where++ = *s++; nbytes+=4;
  586.                 }
  587.                 if (nbytes)
  588.                 (*f->dev->write)(f, (char *)lbconbuf, nbytes);
  589. #else
  590.                 while (bsiz-- > 0) {
  591.                 (void) tty_putchar(f, (long)*s++, RAW);
  592.                 }
  593. #endif
  594.             }
  595.             ret = -1;
  596.         } else {
  597.             ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
  598.         }
  599.         bconbdev = 0;
  600.         return ret;
  601.     }
  602.  
  603. /* Otherwise, we have a real BIOS device */
  604.  
  605.     if (dev == AUXDEV && has_bconmap) {
  606.         dev = curproc->bconmap;
  607.         statdev = dev;
  608.     }
  609. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  610.     else if (dev == 3) {        /* MIDI */
  611.         statdev = 4;
  612.     } else if (dev == 4) {
  613.         statdev = 3;
  614.     } else
  615.         statdev = dev;
  616.         
  617.     s = bconbuf;
  618.     while (bsiz-- > 0) {
  619.         while (!BCOSTAT(statdev)) yield();
  620.         (void)BCONOUT(dev,*s);
  621.         s++;
  622.     }
  623.     bconbdev = 0;
  624.     return 1L;
  625. }
  626.  
  627. /* initialize bios table */
  628.  
  629. #define BIOS_MAX 0x20
  630.  
  631. Func bios_tab[BIOS_MAX] = {
  632.     getmpb,
  633.     ubconstat,
  634.     ubconin,
  635.     ubconout,
  636.  
  637.     rwabs,
  638.     setexc,
  639.     tickcal,
  640.     getbpb,
  641.  
  642.     ubcostat,
  643.     mediach,
  644.     drvmap,
  645.     kbshift,
  646.  
  647.     0, 0, 0, 0,
  648.     0, 0, 0, 0, 0, 0, 0, 0,
  649.     0, 0, 0, 0, 0, 0, 0, 0
  650. };
  651.  
  652. short bios_max = BIOS_MAX;
  653.  
  654. /*
  655.  * BIOS initialization routine: gets keyboard buffer pointers, for the
  656.  * interrupt routine below
  657.  */
  658.  
  659. void
  660. init_bios()
  661. {
  662.     keyrec = (IOREC_T *)Iorec(1);
  663. }
  664.  
  665. /*
  666.  * do_bconin: try to do a bconin function quickly, without
  667.  * blocking. If we can't do it without blocking, we return
  668.  * 0x0123dead and the calling trap #13 code falls through
  669.  * to the normal bconin stuff. We can't block here because
  670.  * the trap #13 code hasn't yet saved registers or other
  671.  * context bits, so sleep() wouldn't work properly.
  672.  */
  673.  
  674. #define WOULDBLOCK 0x0123deadL
  675.  
  676. /* WARNING: syscall.spp assumes that do_bconin never blocks */
  677.  
  678. long ARGS_ON_STACK
  679. do_bconin(dev)
  680.     int dev;
  681. {
  682.     FILEPTR *f;
  683.     long r;
  684.     unsigned char c;
  685.  
  686.     if (dev < MAX_BHANDLE) {
  687.         f = curproc->handle[binput[dev]];
  688.         if (!f) return 0;
  689.         r = 0;
  690.         (void)(*f->dev->ioctl)(f, FIONREAD, &r);
  691.         if (!r) return WOULDBLOCK;    /* data not ready */
  692.         if (is_terminal(f))
  693.             r = tty_getchar(f, RAW);
  694.         else {
  695.             r = (*f->dev->read)(f, (char *)&c, 1L);
  696.             r = (r == 1) ? c : MiNTEOF;
  697.         }
  698.     } else {
  699.         if (!bconstat(dev))
  700.             r = WOULDBLOCK;
  701.         else
  702.             r = bconin(dev);
  703.     }
  704.     return r;
  705. }
  706.  
  707. /*
  708.  * routine for checking keyboard (called by sleep() on any context
  709.  * switch where a keyboard event occured). returns 1 if a special
  710.  * control character was eaten, 0 if not
  711.  */
  712.  
  713. int
  714. checkkeys()
  715. {
  716.     char scan, ch;
  717.     short shift;
  718.     int sig, ret;
  719.     struct tty *tty = &con_tty;
  720.     extern char mshift;        /* for mouse -- see biosfs.c */
  721.     static short oldktail = 0;
  722.  
  723.     ret = 0;
  724.     mshift = kbshift(-1);
  725.     while (oldktail != keyrec->tail) {
  726.  
  727. /* BUG: we really should check the shift status _at the time the key was
  728.  * pressed_, not now!
  729.  */
  730.         sig = 0;
  731.         shift = mshift;
  732.         oldktail += 4;
  733.         if (oldktail >= keyrec->buflen)
  734.             oldktail = 0;
  735.  
  736.         scan = (keyrec->bufaddr + oldktail)[1];
  737. /* function key?? */
  738.         if ( (scan >= 0x3b && scan <= 0x44) ||
  739.              (scan >= 0x54 && scan <= 0x5d) ||
  740.              scan == DEL || scan == UNDO) {
  741.             if ( (shift & CTRLALT) == CTRLALT ) {
  742.                 oldktail = keyrec->head = keyrec->tail;
  743.                 do_func_key(scan);
  744.                 /* do_func_key may have read some keys */
  745.                 oldktail = keyrec->head;
  746.                 mshift = kbshift (-1);
  747.                 ret = 1;
  748.                 continue;
  749.             }
  750.         }
  751.  
  752. /* check for special control keys, etc. */
  753. /* BUG: this doesn't exactly match TOS' behavior, particularly for
  754.  * ^S/^Q
  755.  */
  756.         if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
  757.             ch = (keyrec->bufaddr + keyrec->tail)[3];
  758.             if (ch == UNDEF)
  759.                 ;    /* do nothing */
  760.             else if (ch == tty->tc.t_intrc)
  761.                 sig = SIGINT;
  762.             else if (ch == tty->tc.t_quitc)
  763.                 sig = SIGQUIT;
  764.             else if (ch == tty->ltc.t_suspc)
  765.                 sig = SIGTSTP;
  766.             else if (ch == tty->tc.t_stopc) {
  767.                 tty->state |= TS_HOLD;
  768.                 ret = 1;
  769.                 keyrec->head = oldktail;
  770.                 continue;
  771.             }
  772.             else if (ch == tty->tc.t_startc) {
  773.                 tty->state &= ~TS_HOLD;
  774.                 ret = 1;
  775.                 keyrec->head = oldktail;
  776.                 continue;
  777.             }
  778.             if (sig) {
  779.                 tty->state &= ~TS_HOLD;
  780.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  781.                     oldktail = keyrec->head = keyrec->tail;
  782.                 killgroup(tty->pgrp, sig);
  783.                 ret = 1;
  784.             }
  785.             else if (tty->state & TS_HOLD) {
  786.                 keyrec->head = oldktail;
  787.                 ret = 1;
  788.             }
  789.         }
  790.  
  791.     }
  792.  
  793. /* has someone done select() on the keyboard?? */
  794.     if (tty->rsel && keyrec->head != keyrec->tail)
  795.         wakeselect(tty->rsel);
  796.  
  797.     return ret;
  798. }
  799.  
  800.  
  801. /*
  802.  * special vector stuff: we try to save as many vectors as possible,
  803.  * just in case we need to restore them later
  804.  *
  805.  * BUG: this really should be integrated with the init_intr routine
  806.  * in main.c
  807.  */
  808.  
  809. #define A(x) ((long *)(long)(x))
  810. #define L(x) (long)(x)
  811.  
  812. struct vectab {
  813.     long *addr;
  814.     long def_value;
  815. } VEC[] = {
  816. {A(0x28), 0},    /* Line A */
  817. {A(0x2c), 0},    /* Line F */
  818. {A(0x60), 0},    /* spurious interrupt */
  819. {A(0x64), 0},      /* level 1 interrupt */
  820. {A(0x68), 0},    /* level 2 interrupt */
  821. {A(0x6c), 0},    /* level 3 interrupt */
  822. {A(0x70), 0},    /* level 4 interrupt */
  823. {A(0x74), 0},    /* level 5 interrupt */
  824. {A(0x78), 0},    /* level 6 interrupt */
  825. {A(0x7c), 0},    /* level 7 interrupt */
  826. {A(0x100), 0},    /* various MFP interrupts */
  827. {A(0x104), 0},
  828. {A(0x108), 0},
  829. {A(0x10c), 0},
  830. {A(0x110), 0},
  831. {A(0x114), 0},
  832. {A(0x118), 0},
  833. {A(0x11c), 0},
  834. {A(0x120), 0},
  835. {A(0x124), 0},
  836. {A(0x128), 0},
  837. {A(0x12c), 0},
  838. {A(0x130), 0},
  839. {A(0x134), 0},
  840. {A(0x138), 0},
  841. {A(0x13c), 0},
  842. {A(0x400), 0},    /* etv_timer */
  843. {A(0x4f6), 0},  /* shell_p */
  844.  
  845. {A(0), 0}    /* special tag indicating end of list */
  846. };
  847.  
  848. void
  849. init_vectors() 
  850. {
  851.     struct vectab *v;
  852.  
  853.     for (v = VEC; v->addr; v++) {
  854.         v->def_value = *(v->addr);
  855.     } 
  856. }
  857.  
  858. #if 0    /* bad code */
  859.  
  860. /* unhook a vector; if possible, do this with XBRA, but
  861.  * if that isn't possible force the vector to have the
  862.  * same value it had when MiNT started
  863.  */
  864.  
  865. static void
  866. unhook(v, where)
  867.     struct vectab *v;
  868.     long where;
  869. {
  870.     xbra_vec *xbra;
  871.     long newval;
  872.     int cookie;
  873.  
  874. /* to check for XBRA, we need access to the memory where the
  875.  * vector is
  876.  */
  877.     cookie = prot_temp(where - 12, 16L, -1);
  878.  
  879.     if (cookie == 0)
  880.         newval = v->def_value;
  881.     else {
  882.         xbra = (xbra_vec *)(where - 12);
  883.         if (xbra->xbra_magic == XBRA_MAGIC) {
  884.             newval = (long)xbra->next;
  885.         } else {
  886.             newval = v->def_value;
  887.         }
  888.     }
  889.     *(v->addr) = newval;
  890.  
  891.     (void)prot_temp(where - 12, 16L, cookie);
  892. }
  893. #endif
  894.  
  895. /*
  896.  * unlink_vectors(start, end): any of the "normal" system vectors
  897.  * pointing into a freed memory region must be reset to their
  898.  * default values, or else we'll get a memory protection violation
  899.  * next time the vector gets called
  900.  */
  901.  
  902. void
  903. unlink_vectors(start, end)
  904.     long start, end;
  905. {
  906. #if 0    /* this code is hosed somewhere */
  907.  
  908.     struct vectab *v;
  909.     long where, *p;
  910.     int i;
  911.  
  912. /* first, unhook any VBL handlers */
  913.     i = *((short *)0x454L);    /* i = nvbls */
  914.     p = *((long **)0x456L);    /* p = _vblqueue */
  915.     while (i-- > 0) {
  916.         where = *p;
  917.         if (where >= start && where < end)
  918.             *p = 0;
  919.         p++;
  920.     }
  921.  
  922. /* next, unhook various random vectors */
  923.     for (v = VEC; v->addr; v++) {
  924.         where = *(v->addr);
  925.         if (where >= start && where < end) {
  926.             unhook(v, where);
  927.         }
  928.     }
  929. #endif
  930. }
  931.  
  932.